using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using Mosaic.Interfaces;

namespace StandardPlugins
{
    public class RendererPhotoNoRepetition : IPlugin, IRenderer
    {
        #region IPlugin Member

        public string Author
        {
            get { return "Paul Lange"; }
        }

        public string Description
        {
            get { return "kein Bild doppelt"; }
        }

        public string Name
        {
            get { return "Keine Wiederholung"; }
        }

        #endregion

        #region IRenderer Member

        Size _tileSize;
        ImageLibary _libary;

        public ImageLibary Libary
        {
            get
            {
                return _libary;
            }
            set
            {
                _libary = value;
            }
        }

        public Image RenderMosaic(Color[,] map, ProgressChanged method)
        {
            //weitere Infos speichern
            for (int i = 0; i < _libary.ImageCount; i++)
            {
                _libary[i].Data.Add(false);
            }

            Image img = new Bitmap(map.GetLength(0) * _tileSize.Width, map.GetLength(1) * _tileSize.Height);

            Graphics g = Graphics.FromImage(img);
            Brush b = new SolidBrush(Color.Black);

            //g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            g.FillRectangle(b, 0, 0, img.Width, img.Height);

            ImageInfo info;
            Rectangle destRect, srcRect;

            for (int x = 0; x < map.GetLength(0); x++)
            {
                for (int y = 0; y < map.GetLength(1); y++)
                {
                    //Bestes Bild finden
                    info = this.Libary[this.GetBestImageIndex(map[x, y])];
                    using (Image source = Image.FromFile(info.Path))
                    {
                        //Quell- und Zielgebiet
                        destRect = new Rectangle(x * _tileSize.Width, y * _tileSize.Height, _tileSize.Width, _tileSize.Height);
                        srcRect = new Rectangle(0, 0, source.Width, source.Height);

                        //Bild zeichnen
                        g.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel);
                    }
                }
                method((x + 1) * 100 / map.GetLength(0));
            }

            return img;
        }

        public Size TileSize
        {
            get
            {
                return _tileSize;
            }
            set
            {
                _tileSize = value;
            }
        }

        public RenderType Type
        {
            get { return RenderType.Photo; }
        }

        #endregion

        protected int GetBestImageIndex(Color c)
        {
            double bestPercent = double.MaxValue;
            int bestIndex = 0;

            double difference;
            Color[] passColor;

            int r, g, b;

            for (int i = 0; i < this._libary.ImageCount; i++)
            {
                //Wenn schon benutzt nicht durchrechnen
                if (!(bool)_libary[i].Data[0])
                {
                    //Farben auslesen
                    passColor = new Color[4];
                    passColor[0] = _libary[i].AverageTL;
                    passColor[1] = _libary[i].AverageTR;
                    passColor[2] = _libary[i].AverageBL;
                    passColor[3] = _libary[i].AverageBR;

                    //Farbwerte addieren
                    r = passColor[0].R + passColor[1].R + passColor[2].R + passColor[3].R;
                    g = passColor[0].G + passColor[1].G + passColor[2].G + passColor[3].G;
                    b = passColor[0].B + passColor[1].B + passColor[2].B + passColor[3].B;

                    //absolute Abweichung berechnen
                    r = Math.Abs(c.R - (r / 4));
                    g = Math.Abs(c.G - (g / 4));
                    b = Math.Abs(c.B - (b / 4));

                    //Abweichung
                    difference = r + g + b;
                    difference /= 3 * 255;

                    //Wenn kleiner zuweisen
                    if (difference < bestPercent)
                    {
                        bestPercent = difference;
                        bestIndex = i;
                    }
                }
            }
            //Bestes als Benutzt markieren
            _libary[bestIndex].Data[0] = true;

            return bestIndex;
        }
    }
}
